// Decompiled with JetBrains decompiler
// Type: FibMatrix.Config.MetaKeyValueCollection
// Assembly: FMCommon, Version=1.0.8663.21262, Culture=neutral, PublicKeyToken=null
// MVID: 52773074-FB09-4BA0-8FA9-4782D11D6C17
// Assembly location: /Users/mac/work/RiverGame/com.rivergame.fmframework/Runtime/Plugins/FMCommon.dll

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace FibMatrix.Config
{
  public class MetaKeyValueCollection : IMetaKeyValueCollection
  {
    private static float[] _cacheFloat = new float[1];
    private static int[] _cacheInt = new int[1];
    private string[] _uniqueStrs;
    private int[] _uniqueInts;
    private long[] _uniqueLongs;
    private float[] _uniqueFloats;
    private double[] _uniqueDoubles;
    private Dictionary<string, int> _propNameIndexMap;
    private MetaItemHelper _helper;
    private int[] _propVals;
    private byte[] _propTypes;
    private int _rowValCount;
    private int _extraDataPos;
    private string _metaName;
    private bool _logPerformanceWarning;
    private HashSet<int> _propPerformanceWarningSet;

    public MetaKeyValueCollection(
      string metaName,
      MetaItemHelper helper,
      string[] uniqueStrs,
      int[] uniqueInts,
      long[] uniqueLongs,
      float[] uniqueFloats,
      double[] uniqueDoubles,
      bool logPerformanceWarning = true)
    {
      this._metaName = metaName;
      this._uniqueStrs = uniqueStrs;
      this._uniqueInts = uniqueInts;
      this._uniqueLongs = uniqueLongs;
      this._uniqueFloats = uniqueFloats;
      this._uniqueDoubles = uniqueDoubles;
      this._helper = helper;
      this._extraDataPos = -1;
      this._logPerformanceWarning = logPerformanceWarning;
    }

    public void InitializePropNames()
    {
      int propNum = this._helper.propNum;
      this._propNameIndexMap = new Dictionary<string, int>(propNum);
      this._propVals = new int[propNum];
      this._propTypes = new byte[propNum];
      for (int index = 0; index < propNum; ++index)
      {
        this._propNameIndexMap.Add(this.GetStringByIndex(this._helper.GetPropNameAt(index)), index);
        this._propTypes[index] = (byte) this._helper.GetPropTypeAt(index);
      }
    }

    public void Dispose()
    {
      this._propNameIndexMap.Clear();
      this._propNameIndexMap = (Dictionary<string, int>) null;
      this._uniqueStrs = (string[]) null;
      this._uniqueInts = (int[]) null;
      this._uniqueLongs = (long[]) null;
      this._uniqueFloats = (float[]) null;
      this._uniqueDoubles = (double[]) null;
      this._helper = (MetaItemHelper) null;
    }

    public bool ContainsKey(string key)
    {
      return this._propNameIndexMap.ContainsKey(key) && this._propNameIndexMap[key] < this._rowValCount;
    }

    private int GetRawValAndType(int index, out MetaSerializeType type)
    {
      if (index >= 0 && index < this._rowValCount)
      {
        byte propType = this._propTypes[index];
        type = ((int) propType & 128) == 0 ? (MetaSerializeType) ((uint) propType & (uint) sbyte.MaxValue) : MetaSerializeType.Null;
        return this._propVals[index];
      }
      type = MetaSerializeType.Null;
      return -1;
    }

    public Dictionary<string, string> AllToDictionary()
    {
      Dictionary<string, string> dictionary = new Dictionary<string, string>();
      Dictionary<string, int>.Enumerator enumerator = this._propNameIndexMap.GetEnumerator();
      while (enumerator.MoveNext())
      {
        string key = enumerator.Current.Key;
        MetaSerializeType type;
        int rawValAndType = this.GetRawValAndType(enumerator.Current.Value, out type);
        string str = (string) null;
        switch (type)
        {
          case MetaSerializeType.Null:
            continue;
          case MetaSerializeType.Int:
            str = rawValAndType.ToString();
            break;
          case MetaSerializeType.Float:
            str = this._uniqueFloats[rawValAndType].ToString();
            break;
          case MetaSerializeType.Long:
            str = this._uniqueLongs[rawValAndType].ToString();
            break;
          case MetaSerializeType.Double:
            str = this._uniqueDoubles[rawValAndType].ToString();
            break;
          case MetaSerializeType.String:
            str = this._uniqueStrs[rawValAndType];
            break;
          case MetaSerializeType.IntArray:
            int[] numArray1 = this.DecodeIntArray(rawValAndType, false);
            if (numArray1 != null)
            {
              str = string.Join<int>(",", (IEnumerable<int>) numArray1);
              break;
            }
            continue;
          case MetaSerializeType.FloatArray:
            float[] numArray2 = this.DecodeFloatArray(rawValAndType, true, false);
            if (numArray2 != null)
            {
              str = string.Join<float>(",", (IEnumerable<float>) numArray2);
              break;
            }
            continue;
          case MetaSerializeType.StringArray:
            string[] strArray = this.DecodeStringArray(rawValAndType);
            if (strArray != null)
            {
              str = string.Join(",", strArray);
              break;
            }
            continue;
        }
        dictionary.Add(key, str);
      }
      return dictionary;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public string GetStringByIndex(int index)
    {
      return this._uniqueStrs[index];
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public int GetIntByIndex(int index)
    {
      return this._uniqueInts[index];
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public long GetLongByIndex(int index)
    {
      return this._uniqueLongs[index];
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void FillRowVals()
    {
      this._rowValCount = this._helper.rowValCount;
      this._helper.FillAllVals(this._propTypes, this._propVals, out this._extraDataPos);
    }

    private void PrintPerformanceWarning<T>(
      int keyId,
      T val,
      MetaSerializeType expectedType,
      MetaSerializeType serializedType)
    {
      if (!this._logPerformanceWarning)
        return;
      this._propPerformanceWarningSet = this._propPerformanceWarningSet ?? new HashSet<int>();
      if (this._propPerformanceWarningSet.Contains(keyId))
        return;
      this._propPerformanceWarningSet.Add(keyId);
      Logger.Warning(string.Format("Performance Warning!!!!!! Read Type Conflict, MetaName:{0} PropName:{1} PropValue:{2} ReadType:{3} SerializedType:{4}", (object) this._metaName, (object) this.GetStringByIndex(this._helper.GetPropNameAt(keyId)), (object) val, (object) expectedType, (object) serializedType));
    }

    public double ReadDouble(string key, double defaultVal = 0.0)
    {
      return this.ReadDouble(this.Key2Id(key), defaultVal);
    }

    public double ReadDouble(int keyId, double defaultVal = 0.0)
    {
      MetaSerializeType type;
      int rawValAndType = this.GetRawValAndType(keyId, out type);
      bool flag = false;
      double result;
      switch (type)
      {
        case MetaSerializeType.Int:
          result = (double) rawValAndType;
          break;
        case MetaSerializeType.Float:
          result = (double) this._uniqueFloats[rawValAndType];
          break;
        case MetaSerializeType.Long:
          result = Convert.ToDouble(this._uniqueLongs[rawValAndType]);
          flag = true;
          break;
        case MetaSerializeType.Double:
          result = this._uniqueDoubles[rawValAndType];
          break;
        case MetaSerializeType.String:
          if (!double.TryParse(this._uniqueStrs[rawValAndType], out result))
            result = defaultVal;
          flag = true;
          break;
        case MetaSerializeType.IntArray:
        case MetaSerializeType.FloatArray:
        case MetaSerializeType.StringArray:
          throw new Exception("Can't convert array to double");
        default:
          result = defaultVal;
          break;
      }
      if (flag)
        this.PrintPerformanceWarning<double>(keyId, result, MetaSerializeType.Double, type);
      return result;
    }

    public float ReadFloat(string key, float defaultVal = 0.0f)
    {
      return this.ReadFloat(this.Key2Id(key), defaultVal);
    }

    public float ReadFloat(int keyId, float defaultVal = 0.0f)
    {
      MetaSerializeType type;
      int rawValAndType = this.GetRawValAndType(keyId, out type);
      bool flag = false;
      float result;
      switch (type)
      {
        case MetaSerializeType.Int:
          result = (float) rawValAndType;
          break;
        case MetaSerializeType.Float:
          result = this._uniqueFloats[rawValAndType];
          break;
        case MetaSerializeType.Long:
          result = Convert.ToSingle(this._uniqueLongs[rawValAndType]);
          flag = true;
          break;
        case MetaSerializeType.Double:
          result = (float) this._uniqueDoubles[rawValAndType];
          break;
        case MetaSerializeType.String:
          if (!float.TryParse(this._uniqueStrs[rawValAndType], out result))
            result = defaultVal;
          flag = true;
          break;
        case MetaSerializeType.IntArray:
        case MetaSerializeType.StringArray:
          throw new Exception("Can't convert array to float");
        case MetaSerializeType.FloatArray:
          result = this.DecodeFloatArray(rawValAndType, true, true)[0];
          break;
        default:
          result = defaultVal;
          break;
      }
      if (flag)
        this.PrintPerformanceWarning<float>(keyId, result, MetaSerializeType.Float, type);
      return result;
    }

    public int ReadInt(string key, int defaultVal = -1)
    {
      return this.ReadInt(this.Key2Id(key), defaultVal);
    }

    public int ReadInt(int keyId, int defaultVal = -1)
    {
      MetaSerializeType type;
      int rawValAndType = this.GetRawValAndType(keyId, out type);
      bool flag = false;
      int result;
      switch (type)
      {
        case MetaSerializeType.Int:
          result = rawValAndType;
          break;
        case MetaSerializeType.Float:
          result = (int) this._uniqueFloats[rawValAndType];
          break;
        case MetaSerializeType.Long:
          result = Convert.ToInt32(this._uniqueLongs[rawValAndType]);
          flag = true;
          break;
        case MetaSerializeType.Double:
          result = (int) this._uniqueDoubles[rawValAndType];
          break;
        case MetaSerializeType.String:
          if (!int.TryParse(this._uniqueStrs[rawValAndType], out result))
            result = defaultVal;
          flag = true;
          break;
        case MetaSerializeType.IntArray:
          result = this.DecodeIntArray(rawValAndType, true)[0];
          break;
        case MetaSerializeType.FloatArray:
        case MetaSerializeType.StringArray:
          throw new Exception("Can't convert array to int");
        default:
          result = defaultVal;
          break;
      }
      if (flag)
        this.PrintPerformanceWarning<int>(keyId, result, MetaSerializeType.Int, type);
      return result;
    }

    public long ReadLong(string key, long defaultVal = -1)
    {
      return this.ReadLong(this.Key2Id(key), defaultVal);
    }

    public long ReadLong(int keyId, long defaultVal = -1)
    {
      MetaSerializeType type;
      int rawValAndType = this.GetRawValAndType(keyId, out type);
      bool flag = false;
      long result;
      switch (type)
      {
        case MetaSerializeType.Int:
          result = (long) rawValAndType;
          break;
        case MetaSerializeType.Float:
          result = (long) this._uniqueFloats[rawValAndType];
          break;
        case MetaSerializeType.Long:
          result = this._uniqueLongs[rawValAndType];
          break;
        case MetaSerializeType.Double:
          result = (long) this._uniqueDoubles[rawValAndType];
          break;
        case MetaSerializeType.String:
          if (!long.TryParse(this._uniqueStrs[rawValAndType], out result))
            result = defaultVal;
          flag = true;
          break;
        case MetaSerializeType.IntArray:
        case MetaSerializeType.FloatArray:
        case MetaSerializeType.StringArray:
          throw new Exception("Can't convert array to long");
        default:
          result = defaultVal;
          break;
      }
      if (flag)
        this.PrintPerformanceWarning<long>(keyId, result, MetaSerializeType.Long, type);
      return result;
    }

    public string ReadString(string key, string defaultVal = null)
    {
      return this.ReadString(this.Key2Id(key), defaultVal);
    }

    public string ReadString(int keyId, string defaultVal = null)
    {
      MetaSerializeType type;
      int rawValAndType = this.GetRawValAndType(keyId, out type);
      bool flag = false;
      string val;
      switch (type)
      {
        case MetaSerializeType.Int:
          val = rawValAndType.ToString();
          flag = true;
          break;
        case MetaSerializeType.Float:
          val = this._uniqueFloats[rawValAndType].ToString();
          flag = true;
          break;
        case MetaSerializeType.Long:
          val = this._uniqueLongs[rawValAndType].ToString();
          flag = true;
          break;
        case MetaSerializeType.Double:
          val = this._uniqueDoubles[rawValAndType].ToString();
          flag = true;
          break;
        case MetaSerializeType.String:
          val = this._uniqueStrs[rawValAndType];
          break;
        case MetaSerializeType.IntArray:
          int[] numArray1 = this.DecodeIntArray(rawValAndType, false);
          val = numArray1 == null ? defaultVal : numArray1.ToString();
          flag = true;
          break;
        case MetaSerializeType.FloatArray:
          float[] numArray2 = this.DecodeFloatArray(rawValAndType, true, false);
          val = numArray2 == null ? defaultVal : numArray2.ToString();
          flag = true;
          break;
        case MetaSerializeType.StringArray:
          string[] strArray = this.DecodeStringArray(rawValAndType);
          val = strArray == null ? defaultVal : strArray.ToString();
          flag = true;
          break;
        default:
          val = defaultVal;
          break;
      }
      if (flag)
        this.PrintPerformanceWarning<string>(keyId, val, MetaSerializeType.String, type);
      return val;
    }

    public int[] ReadIntArray(string key, int[] defaultVal = null)
    {
      return this.ReadIntArray(this.Key2Id(key), defaultVal);
    }

    public int[] ReadIntArray(int keyId, int[] defaultVal = null)
    {
      MetaSerializeType type;
      bool typeConversion;
      int[] val = this.DoReadIntArray(this.GetRawValAndType(keyId, out type), type, defaultVal, out typeConversion);
      if (typeConversion)
        this.PrintPerformanceWarning<int[]>(keyId, val, MetaSerializeType.IntArray, type);
      return val;
    }

    private int[] DoReadIntArray(
      int indexOrVal,
      MetaSerializeType type,
      int[] defaultVal,
      out bool typeConversion)
    {
      typeConversion = false;
      switch (type)
      {
        case MetaSerializeType.Null:
          return defaultVal;
        case MetaSerializeType.Int:
          typeConversion = true;
          return new int[1]{ indexOrVal };
        case MetaSerializeType.IntArray:
          return this.DecodeIntArray(indexOrVal, false);
        case MetaSerializeType.StringArray:
          typeConversion = true;
          return ConfigFormatUtil.ConvertStringArrayToIntArray(this.DecodeStringArray(indexOrVal));
        default:
          throw new Exception("Can't convert type " + type.ToString() + " to int array");
      }
    }

    private unsafe int[] DecodeIntArray(int indexOrVal, bool onlyGetFirst = false)
    {
      fixed (byte* buffers = this._helper.buffer)
      {
        int pos1 = this._extraDataPos + indexOrVal;
        int length = ConfigFormatUtil.Read7BitEncodedInt(buffers, ref pos1);
        int[] numArray;
        if (onlyGetFirst)
        {
          if (length != 1)
            throw new Exception("Can't convert int array which length != 1 to single int, count " + length.ToString());
          numArray = MetaKeyValueCollection._cacheInt;
        }
        else
          numArray = new int[length];
        if (length >= 4)
        {
          int num = pos1;
          int pos2 = pos1 + ((length & 3) == 0 ? length >> 2 : (length >> 2) + 1);
          for (int index = 0; index < length; ++index)
          {
            byte byteNum = ConfigFormatUtil.DecodeIntByteLen((byte) ((int) (buffers + num)[index / 4] >> (index % 4 << 1) & 3));
            numArray[index] = ConfigFormatUtil.ReadInt32(buffers, ref pos2, byteNum);
          }
        }
        else
        {
          for (int index = 0; index < length; ++index)
            numArray[index] = ConfigFormatUtil.Read7BitEncodedInt(buffers, ref pos1);
        }
        return numArray;
      }
    }

    public float[] ReadFloatArray(string key, float[] defaultVal = null)
    {
      return this.ReadFloatArray(this.Key2Id(key), defaultVal);
    }

    public float[] ReadFloatArray(int keyId, float[] defaultVal = null)
    {
      MetaSerializeType type;
      bool typeConversion;
      float[] val = this.DoReadFloatArray(this.GetRawValAndType(keyId, out type), type, defaultVal, out typeConversion);
      if (typeConversion)
        this.PrintPerformanceWarning<float[]>(keyId, val, MetaSerializeType.FloatArray, type);
      return val;
    }

    private float[] DoReadFloatArray(
      int indexOrVal,
      MetaSerializeType type,
      float[] defaultVal,
      out bool typeConversion)
    {
      typeConversion = false;
      switch (type)
      {
        case MetaSerializeType.Null:
          return defaultVal;
        case MetaSerializeType.Int:
          typeConversion = true;
          return new float[1]{ (float) indexOrVal };
        case MetaSerializeType.Float:
          typeConversion = true;
          return new float[1]
          {
            this._uniqueFloats[indexOrVal]
          };
        case MetaSerializeType.IntArray:
          return this.DecodeFloatArray(indexOrVal, false, false);
        case MetaSerializeType.FloatArray:
          return this.DecodeFloatArray(indexOrVal, true, false);
        case MetaSerializeType.StringArray:
          typeConversion = true;
          return ConfigFormatUtil.ConvertStringArrayToFloatArray(this.DecodeStringArray(indexOrVal));
        default:
          throw new Exception("Can't convert type " + type.ToString() + " to int array");
      }
    }

    private unsafe float[] DecodeFloatArray(int indexOrVal, bool sourceIsFloat, bool onlyGetFirst = false)
    {
      fixed (byte* buffers = this._helper.buffer)
      {
        int pos1 = this._extraDataPos + indexOrVal;
        int length = ConfigFormatUtil.Read7BitEncodedInt(buffers, ref pos1);
        float[] numArray;
        if (onlyGetFirst)
        {
          if (length != 1)
            throw new Exception("Can't convert float array which length != 1 to single float");
          numArray = MetaKeyValueCollection._cacheFloat;
        }
        else
          numArray = new float[length];
        if (length >= 4)
        {
          int num = pos1;
          int pos2 = pos1 + ((length & 3) == 0 ? length >> 2 : (length >> 2) + 1);
          for (int index1 = 0; index1 < length; ++index1)
          {
            byte byteNum = ConfigFormatUtil.DecodeOtherByteLen((byte) ((int) (buffers + num)[index1 / 4] >> (index1 % 4 << 1) & 3));
            int index2 = ConfigFormatUtil.ReadInt32(buffers, ref pos2, byteNum);
            numArray[index1] = sourceIsFloat ? this._uniqueFloats[index2] : (float) index2;
          }
        }
        else
        {
          for (int index1 = 0; index1 < length; ++index1)
          {
            int index2 = ConfigFormatUtil.Read7BitEncodedInt(buffers, ref pos1);
            numArray[index1] = sourceIsFloat ? this._uniqueFloats[index2] : (float) index2;
          }
        }
        return numArray;
      }
    }

    public string[] ReadStringArray(string key, string[] defaultVal = null)
    {
      return this.ReadStringArray(this.Key2Id(key), defaultVal);
    }

    public string[] ReadStringArray(int keyId, string[] defaultVal = null)
    {
      MetaSerializeType type;
      bool typeConversion;
      string[] val = this.DoReadStringArray(this.GetRawValAndType(keyId, out type), type, defaultVal, out typeConversion);
      if (typeConversion)
        this.PrintPerformanceWarning<string[]>(keyId, val, MetaSerializeType.StringArray, type);
      return val;
    }

    private string[] DoReadStringArray(
      int indexOrVal,
      MetaSerializeType type,
      string[] defaultVal,
      out bool typeConversion)
    {
      typeConversion = false;
      switch (type)
      {
        case MetaSerializeType.Null:
          return defaultVal;
        case MetaSerializeType.Int:
          typeConversion = true;
          return new string[1]{ indexOrVal.ToString() };
        case MetaSerializeType.Float:
          typeConversion = true;
          return new string[1]
          {
            this._uniqueFloats[indexOrVal].ToString()
          };
        case MetaSerializeType.IntArray:
          typeConversion = true;
          return ConfigFormatUtil.ConvertIntArrayToStringArray(this.DecodeIntArray(indexOrVal, false));
        case MetaSerializeType.FloatArray:
          typeConversion = true;
          return ConfigFormatUtil.ConvertFloatArrayToStringArray(this.DecodeFloatArray(indexOrVal, true, false));
        case MetaSerializeType.StringArray:
          return this.DecodeStringArray(indexOrVal);
        default:
          throw new Exception("Can't convert type " + type.ToString() + " to int array");
      }
    }

    private unsafe string[] DecodeStringArray(int indexOrVal)
    {
      fixed (byte* buffers = this._helper.buffer)
      {
        int pos1 = this._extraDataPos + indexOrVal;
        int length = ConfigFormatUtil.Read7BitEncodedInt(buffers, ref pos1);
        string[] strArray = new string[length];
        if (length >= 4)
        {
          int num = pos1;
          int pos2 = pos1 + ((length & 3) == 0 ? length >> 2 : (length >> 2) + 1);
          for (int index = 0; index < length; ++index)
          {
            byte byteNum = ConfigFormatUtil.DecodeOtherByteLen((byte) ((int) (buffers + num)[index / 4] >> (index % 4 << 1) & 3));
            strArray[index] = this._uniqueStrs[ConfigFormatUtil.ReadInt32(buffers, ref pos2, byteNum)];
          }
        }
        else
        {
          for (int index = 0; index < length; ++index)
            strArray[index] = this._uniqueStrs[ConfigFormatUtil.Read7BitEncodedInt(buffers, ref pos1)];
        }
        return strArray;
      }
    }

    public int Key2Id(string key)
    {
      int num;
      return this._propNameIndexMap.TryGetValue(key, out num) ? num : -1;
    }
  }
}
